package com.bbf.springmvcdemo.feature;

import com.bbf.springmvcdemo.util.BaseUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.servlet.mvc.support.RedirectAttributesModelMap;

import java.beans.PropertyEditorSupport;
import java.util.Date;

/**
 * 全局控制器
 * @author BBF
 */
@ControllerAdvice
public class BaseControllerAdvice {
  private static final Logger LOGGER = LoggerFactory.getLogger(BaseControllerAdvice.class);
  private static final String[] PARSE_PATTERNS =
      new String[]{BaseUtil.DATE_FORMAT1, BaseUtil.DATE_FORMAT2, BaseUtil.DATE_FORMAT3};

  private final CustomProperties customProperties = CustomProperties.getInstance();
  private static final String GLOBAL = "global";

  /**
   * 全局绑定，所有注解@RequestMapping的方法都可以获得键值对
   * @param model Model
   */
  @ModelAttribute
  public void addAttributes(Model model, RedirectAttributesModelMap rModel) {
    if (!model.containsAttribute(GLOBAL) && !rModel.containsAttribute(GLOBAL)) {
      model.addAttribute(GLOBAL, customProperties);
    }
  }

  /**
   * 初始化数据绑定
   * <ol><li>将所有传递进来的String进行HTML编码，防止XSS攻击</li>
   * <li>将字段中Date类型转换为String类型</li></ol>
   * @param binder WebDataBinder
   */
  @InitBinder
  public void initBinder(final WebDataBinder binder) {
    // String类型转换，防止XSS攻击
    binder.registerCustomEditor(String.class, new PropertyEditorSupport() {
      @Override
      public void setAsText(String text) {
        setValue(text);
      }

      //接收的值不做任何转换，否则数据库字段会超长。例如 < 为一个字符，转换后 &lt; 四字符
      @Override
      public String getAsText() {
        Object value = getValue();
        return null == value ? StringUtils.EMPTY : StringEscapeUtils.escapeHtml4(value.toString());
      }
    });
    // Date 类型转换
    binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
      @Override
      public void setAsText(String text) {
        if (StringUtils.isNotBlank(text)) {
          try {
            setValue(DateUtils.parseDate(text, PARSE_PATTERNS));
          } catch (Exception ex) {
            LOGGER.info("[BaseControllerAdvice.Date]{}，text = {}", ex.getMessage(), text);
          }
        }
      }
    });

    binder.registerCustomEditor(ResponseEntity.class, new PropertyEditorSupport() {
      @Override
      public void setAsText(String text) {
        //接收的值不做任何转换，否则数据库字段会超长。例如 < 为一个字符，转换后 &lt; 四字符
        setValue(text);
      }

      @Override
      public String getAsText() {
        Object value = getValue();
        return null == value ? StringUtils.EMPTY : StringEscapeUtils.escapeHtml4(value.toString());
      }
    });
  }
}
